import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';

/// Mock平台实现，用于模拟NFC操作
class MockNfcPlatform {
  static const MethodChannel _channel = MethodChannel('flutter_nfc_kit/method');
  static const EventChannel _eventChannel = EventChannel('flutter_nfc_kit/event');
  
  /// 模拟的NFC状态
  static String _nfcAvailability = 'available';
  
  /// 模拟的标签数据
  static Map<String, dynamic> _mockTag = {
    'type': 'iso7816',
    'id': '04:12:34:56:78:90:AB',
    'standard': 'ISO 14443-4 (Type A)',
    'atqa': '0400',
    'sak': '20',
    'historicalBytes': '',
    'protocolInfo': '',
    'applicationData': '',
    'hiLayerResponse': '',
    'manufacturer': '',
    'systemCode': '',
    'dsfId': '',
    'ndefAvailable': true,
    'ndefType': 'Type 4',
    'ndefCapacity': 8192,
    'ndefWritable': true,
    'ndefCanMakeReadOnly': false,
    'webUSBCustomProbeData': '',
    'mifareInfo': null,
  };
  
  /// 模拟的NDEF数据
  static List<Map<String, dynamic>> _mockNdefRecords = [
    {
      'identifier': '',
      'payload': '48656C6C6F20576F726C64', // "Hello World" in hex
      'type': '54', // Text record type
      'typeNameFormat': 'nfcWellKnown',
    },
  ];
  
  /// 模拟的MIFARE扇区认证状态
  static Map<int, bool> _authenticatedSectors = {};
  
  /// 模拟的MIFARE块数据
  static Map<int, Uint8List> _blockData = {};
  
  /// 是否模拟会话活跃状态
  static bool _isSessionActive = false;
  
  /// 是否模拟轮询超时
  static bool _shouldTimeout = false;
  
  /// 是否模拟平台异常
  static bool _shouldThrowException = false;
  
  /// 异常代码和消息
  static String _exceptionCode = '500';
  static String _exceptionMessage = 'Mock platform exception';

  /// 设置Mock平台的初始方法处理器
  static void setupMockMethodCallHandler() {
    TestWidgetsFlutterBinding.ensureInitialized();
    TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
        .setMockMethodCallHandler(_channel, _mockMethodCallHandler);
  }

  /// 设置Mock平台的事件流处理器
  static void setupMockStreamHandler() {
    // 简化实现，只设置基本的流处理器
    TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
        .setMockStreamHandler(_eventChannel, null);
  }

  /// 清理Mock平台设置
  static void tearDown() {
    if (TestWidgetsFlutterBinding.ensureInitialized() != null) {
      TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
          .setMockMethodCallHandler(_channel, null);
      TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
          .setMockStreamHandler(_eventChannel, null);
    }
    
    // 重置状态
    _isSessionActive = false;
    _shouldTimeout = false;
    _shouldThrowException = false;
    _authenticatedSectors.clear();
    _blockData.clear();
  }

  /// 设置NFC可用性状态
  static void setNfcAvailability(String availability) {
    _nfcAvailability = availability;
  }

  /// 设置模拟标签数据
  static void setMockTag(Map<String, dynamic> tagData) {
    _mockTag = Map.from(tagData);
  }

  /// 设置模拟NDEF记录
  static void setMockNdefRecords(List<Map<String, dynamic>> records) {
    _mockNdefRecords = List.from(records);
  }

  /// 设置轮询超时模拟
  static void setShouldTimeout(bool timeout) {
    _shouldTimeout = timeout;
  }

  /// 设置异常模拟
  static void setShouldThrowException(bool throwException, {String? code, String? message}) {
    _shouldThrowException = throwException;
    if (code != null) _exceptionCode = code;
    if (message != null) _exceptionMessage = message;
  }

  /// 认证MIFARE扇区
  static void authenticateSector(int sector, bool success) {
    _authenticatedSectors[sector] = success;
  }

  /// 设置MIFARE块数据
  static void setBlockData(int blockIndex, Uint8List data) {
    _blockData[blockIndex] = data;
  }

  /// 获取会话状态
  static bool get isSessionActive => _isSessionActive;

  /// Mock方法调用处理器
  static Future<dynamic> _mockMethodCallHandler(MethodCall call) async {
    if (_shouldThrowException) {
      throw PlatformException(
        code: _exceptionCode,
        message: _exceptionMessage,
        details: null,
      );
    }

    switch (call.method) {
      case 'getNFCAvailability':
        return _nfcAvailability;

      case 'poll':
        if (_shouldTimeout) {
          await Future.delayed(const Duration(milliseconds: 100));
          throw PlatformException(
            code: '408',
            message: 'Polling tag timeout',
            details: null,
          );
        }
        
        _isSessionActive = true;
        return jsonEncode(_mockTag);

      case 'finish':
        _isSessionActive = false;
        _authenticatedSectors.clear();
        return null;

      case 'readNDEF':
        if (!_isSessionActive) {
          throw PlatformException(
            code: '406',
            message: 'No tag polled',
            details: null,
          );
        }
        return jsonEncode(_mockNdefRecords);

      case 'writeNDEF':
        if (!_isSessionActive) {
          throw PlatformException(
            code: '406',
            message: 'No tag polled',
            details: null,
          );
        }
        
        final data = call.arguments['data'] as String;
        final records = jsonDecode(data) as List<dynamic>;
        _mockNdefRecords = records.cast<Map<String, dynamic>>();
        return null;

      case 'makeNdefReadOnly':
        if (!_isSessionActive) {
          throw PlatformException(
            code: '406',
            message: 'No tag polled',
            details: null,
          );
        }
        return null;

      case 'authenticateSector':
        if (!_isSessionActive) {
          throw PlatformException(
            code: '406',
            message: 'No tag polled',
            details: null,
          );
        }
        
        final index = call.arguments['index'] as int;
        return _authenticatedSectors[index] ?? false;

      case 'readBlock':
        if (!_isSessionActive) {
          throw PlatformException(
            code: '406',
            message: 'No tag polled',
            details: null,
          );
        }
        
        final index = call.arguments['index'] as int;
        final data = _blockData[index];
        if (data == null) {
          // 返回默认数据
          return Uint8List.fromList(List.generate(16, (i) => i));
        }
        return data;

      case 'writeBlock':
        if (!_isSessionActive) {
          throw PlatformException(
            code: '406',
            message: 'No tag polled',
            details: null,
          );
        }
        
        final index = call.arguments['index'] as int;
        final data = call.arguments['data'];
        if (data is Uint8List) {
          _blockData[index] = data;
        } else if (data is String) {
          // 假设是十六进制字符串
          _blockData[index] = _hexStringToBytes(data);
        }
        return null;

      case 'readSector':
        if (!_isSessionActive) {
          throw PlatformException(
            code: '406',
            message: 'No tag polled',
            details: null,
          );
        }
        
        final index = call.arguments['index'] as int;
        // 返回64字节的扇区数据
        return Uint8List.fromList(List.generate(64, (i) => (index * 64 + i) % 256));

      case 'transceive':
        if (!_isSessionActive) {
          throw PlatformException(
            code: '406',
            message: 'No tag polled',
            details: null,
          );
        }
        
        final data = call.arguments['data'];
        // 模拟简单的APDU响应
        if (data is String) {
          return '9000'; // Success response
        } else if (data is Uint8List) {
          return Uint8List.fromList([0x90, 0x00]); // Success response
        }
        return null;

      case 'restartPolling':
        return null;

      case 'setIosAlertMessage':
        return null;

      default:
        throw PlatformException(
          code: '405',
          message: 'Method ${call.method} not supported',
          details: null,
        );
    }
  }

  /// 将十六进制字符串转换为字节数组
  static Uint8List _hexStringToBytes(String hex) {
    final cleanHex = hex.replaceAll(RegExp(r'[^0-9A-Fa-f]'), '');
    final bytes = <int>[];
    for (int i = 0; i < cleanHex.length; i += 2) {
      final hexByte = cleanHex.substring(i, i + 2);
      bytes.add(int.parse(hexByte, radix: 16));
    }
    return Uint8List.fromList(bytes);
  }
}

/// Mock测试辅助工具
class MockNfcTestHelper {
  /// 创建MIFARE Classic标签数据
  static Map<String, dynamic> createMifareClassicTag({
    String id = '04:12:34:56',
    String type = 'MIFARE_CLASSIC_1K',
    int size = 1024,
    int blockCount = 64,
    int sectorCount = 16,
  }) {
    return {
      'type': 'mifare_classic',
      'id': id,
      'standard': 'ISO 14443-3 (Type A)',
      'atqa': '0400',
      'sak': '08',
      'historicalBytes': '',
      'protocolInfo': '',
      'applicationData': '',
      'hiLayerResponse': '',
      'manufacturer': '',
      'systemCode': '',
      'dsfId': '',
      'ndefAvailable': false,
      'ndefType': '',
      'ndefCapacity': 0,
      'ndefWritable': false,
      'ndefCanMakeReadOnly': false,
      'webUSBCustomProbeData': '',
      'mifareInfo': {
        'type': type,
        'size': size,
        'blockSize': 16,
        'blockCount': blockCount,
        'sectorCount': sectorCount,
      },
    };
  }

  /// 创建ISO 7816标签数据
  static Map<String, dynamic> createIso7816Tag({
    String id = '04:12:34:56:78:90:AB',
    bool ndefAvailable = true,
    int ndefCapacity = 8192,
  }) {
    return {
      'type': 'iso7816',
      'id': id,
      'standard': 'ISO 14443-4 (Type A)',
      'atqa': '0400',
      'sak': '20',
      'historicalBytes': 'ABC123',
      'protocolInfo': '',
      'applicationData': '',
      'hiLayerResponse': '',
      'manufacturer': '',
      'systemCode': '',
      'dsfId': '',
      'ndefAvailable': ndefAvailable,
      'ndefType': 'Type 4',
      'ndefCapacity': ndefCapacity,
      'ndefWritable': true,
      'ndefCanMakeReadOnly': false,
      'webUSBCustomProbeData': '',
      'mifareInfo': null,
    };
  }

  /// 创建NDEF文本记录
  static Map<String, dynamic> createNdefTextRecord(String text, {String language = 'en'}) {
    // 简化的NDEF文本记录格式
    final languageBytes = language.codeUnits;
    final textBytes = text.codeUnits;
    final payload = [languageBytes.length, ...languageBytes, ...textBytes];
    
    return {
      'identifier': '',
      'payload': payload.map((b) => b.toRadixString(16).padLeft(2, '0')).join(''),
      'type': '54', // Text record type
      'typeNameFormat': 'nfcWellKnown',
    };
  }

  /// 创建NDEF URI记录
  static Map<String, dynamic> createNdefUriRecord(String uri) {
    final uriBytes = uri.codeUnits;
    // 0x00表示没有URI前缀简化
    final payload = [0x00, ...uriBytes];
    
    return {
      'identifier': '',
      'payload': payload.map((b) => b.toRadixString(16).padLeft(2, '0')).join(''),
      'type': '55', // URI record type
      'typeNameFormat': 'nfcWellKnown',
    };
  }

  /// 创建自定义错误场景
  static void setupErrorScenario(String code, String message) {
    MockNfcPlatform.setShouldThrowException(true, code: code, message: message);
  }

  /// 创建超时场景
  static void setupTimeoutScenario() {
    MockNfcPlatform.setShouldTimeout(true);
  }

  /// 重置到正常状态
  static void resetToNormalState() {
    MockNfcPlatform.setShouldThrowException(false);
    MockNfcPlatform.setShouldTimeout(false);
    MockNfcPlatform.setNfcAvailability('available');
  }
}

/// 测试用的MIFARE密钥常量
class TestMifareKeys {
  static const String defaultKey = 'FFFFFFFFFFFF';
  static const String mfcKeyA = 'A0A1A2A3A4A5';
  static const String mfcKeyB = 'B0B1B2B3B4B5';
  static const String customKey = '123456789ABC';
  
  static final Uint8List defaultKeyBytes = Uint8List.fromList([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]);
  static final Uint8List mfcKeyABytes = Uint8List.fromList([0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5]);
  static final Uint8List mfcKeyBBytes = Uint8List.fromList([0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5]);
}

/// 测试用的APDU命令常量
class TestApduCommands {
  static const String selectApplicationCmd = '00A4040007A0000002471001';
  static const String selectFileCmd = '00A4020C02F001';
  static const String readRecordCmd = '00B2010C1D';
  static const String verifyPinCmd = '0020000108313233343536373839';
  
  static final Uint8List selectApplicationBytes = Uint8List.fromList([
    0x00, 0xA4, 0x04, 0x00, 0x07, 0xA0, 0x00, 0x00, 0x02, 0x47, 0x10, 0x01
  ]);
  
  static const String successResponse = '9000';
  static const String fileNotFoundResponse = '6A82';
  static const String wrongPinResponse = '63C2';
  
  static final Uint8List successResponseBytes = Uint8List.fromList([0x90, 0x00]);
  static final Uint8List fileNotFoundResponseBytes = Uint8List.fromList([0x6A, 0x82]);
}